package com.eshop.config;

import cn.hutool.json.JSON;
import cn.hutool.json.JSONUtil;
import com.eshop.filter.JwtSecurityFilter;
import com.eshop.pojo.Menu;
import com.eshop.pojo.Resource;
import com.eshop.pojo.Role;
import com.eshop.pojo.User;
import com.eshop.service.MenuService;
import com.eshop.service.ResourceService;
import com.eshop.service.RoleService;
import com.eshop.utils.JwtUtil;
import com.eshop.vo.ResultVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import java.util.Collection;
import java.util.List;

@Configuration
public class WebSecurityConfig {
    @Autowired
    StringRedisTemplate redisTemplate;
    @Autowired
    ResourceService resourceService;
    @Autowired
    RoleService roleService;

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.csrf().disable();
        JwtSecurityFilter jwtSecurityFilter = new JwtSecurityFilter();
        http.addFilterBefore(jwtSecurityFilter, UsernamePasswordAuthenticationFilter.class);
        http.authorizeHttpRequests(ahr ->
                ahr.requestMatchers("/login", "/error").permitAll()
                        .anyRequest().access((authentication, object) -> {
                            String uri = object.getRequest().getRequestURI();
                            List<Resource> resourceList = resourceService.list();
                            boolean quanxian = false;
                            for (Resource resource : resourceList) {
                                System.out.println(uri);
                                if (uri.startsWith(resource.getPermission())) {
                                    quanxian = true;
                                    Role role = roleService.getRoleByResourceId(resource.getId());
                                    Collection<? extends GrantedAuthority> authorities = authentication.get().getAuthorities();
                                    for (GrantedAuthority authority : authorities) {
                                        if (authority.getAuthority().equals(role.getName())) {
                                            return new AuthorizationDecision(true);
                                        }

                                    }
                                }
                                break;
                            }
                            if (!quanxian && !(authentication instanceof AnonymousAuthenticationToken)) {
                                return new AuthorizationDecision(true);
                            }
                            System.out.println("无权限");
                            return new AuthorizationDecision(false);
                        })
        );
        http.formLogin(login ->
                login.loginProcessingUrl("/login")
                        .successHandler((request, response, authentication) -> {
                            response.setContentType("application/json;charset=utf-8");
                            String token = JwtUtil.createToken(authentication);
                            User principal = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
                            redisTemplate.opsForValue().set(token, JSONUtil.toJsonStr(principal));
                            response.getWriter().write(JSONUtil.toJsonStr(ResultVo.success(token)));
                        }).failureHandler((request, response, exception) -> {
                            response.setContentType("application/json;charset=utf-8");
                            response.getWriter().write(JSONUtil.toJsonStr(ResultVo.error("登录失败:" + exception.getMessage())));
                        }));
        return http.build();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public WebSecurityCustomizer webSecurityCustomizer() {
        return (web -> web.ignoring().requestMatchers("/image/**"));
    }
}
